import { proxyRefs } from "../reactivity";
import { shallowReadonly } from "../reactivity/reactive";
import { isObject } from "../shared/index";
import { emit } from "./componentEmit";
import { initProps } from "./componentProps";
import { PublicInstanceProxyHandlers } from "./componentPublicInstance";
import { initSlots } from "./componentSlots";

export function createComponentInstance(vnode, parent) {
    const component = {
        vnode,
        type: vnode.type,
        next: null,
        setupState: {},
        props: {},
        slots: {},
        provides: parent ? parent.provides : {},
        parent,
        isMounted: false,
        subTree: {},
        emit: () => { }
    };

    component.emit = emit.bind(null, component) as any;

    return component
}

export function setupComponent(instance) {
    initProps(instance, instance.vnode.props);
    initSlots(instance, instance.vnode.children);

    setupStatefulComponent(instance);
}

function setupStatefulComponent(instance: any) {
    const Component = instance.type;

    instance.proxy = new Proxy({ _: instance }, PublicInstanceProxyHandlers)

    const { setup } = Component;
    if (setup) {
        // 当前的实例对象
        setCurrentInstance(instance);

        // 返回函数或者对象
        // props是只读的，无法修改父元素的属性，所以用shallowReadonly修饰
        const setupResult = setup(shallowReadonly(instance.props), {
            emit: instance.emit
        });

        setCurrentInstance(null);

        handleSetupResult(instance, setupResult);
    }
}

function handleSetupResult(instance, setupResult) {
    // setupResult是函数或者对象
    // TODO 函数

    // 对象
    if (typeof setupResult === 'object') {
        instance.setupState = proxyRefs(setupResult);
    }

    finishComponentSetup(instance);
}
function finishComponentSetup(instance: any) {
    const Component = instance.type;
    if (!instance.render) {
        // 如果 compile 有值 并且当组件没有 render 函数，那么就需要把 template 编译成 render 函数
        if (compile && !Component.render) {
            if (Component.template) {
                // 这里就是 runtime 模块和 compile 模块结合点
                const template = Component.template;
                Component.render = compile(template);
            }
        }

        instance.render = Component.render;
    }
}

let currentInstance = null;
export function getCurrentInstance() {
    return currentInstance;
}

export function setCurrentInstance(instance) {
    currentInstance = instance;
}

let compile;
export function registerRuntimeCompiler(_compile) {
    compile = _compile;
}